#include "LuminePipeline.hpp"
#include <iostream>
#include <filesystem>
#include <fstream>
#include "Core/Texture/TextureManager.hpp"
void Lumine::LuminePipeline::createDescriptorSetLayout()
{
    vk::DescriptorSetLayoutBinding uboLayoutBindings(0, vk::DescriptorType::eUniformBuffer, 1, vk::ShaderStageFlagBits::eVertex, nullptr);

    vk::DescriptorSetLayoutBinding samplerLayoutBinding{};
    samplerLayoutBinding.setBinding(1)
        .setDescriptorType(vk::DescriptorType::eCombinedImageSampler)
        .setDescriptorCount(1)
        .setStageFlags(vk::ShaderStageFlagBits::eFragment);

    std::array<vk::DescriptorSetLayoutBinding, 2> bindings = {uboLayoutBindings, samplerLayoutBinding};
    vk::DescriptorSetLayoutCreateInfo layoutInfo({}, bindings.size(), bindings.data());

    descriptorSetLayout = vk::raii::DescriptorSetLayout(LumineContext::Get().Device(), layoutInfo);
}

void Lumine::LuminePipeline::CreatePipeline_Internal(vk::Format format)
{
    // 获取着色器
    std::cout << std::filesystem::current_path() << std::endl;
    auto shaderCode = readFile("Shaders/slang.spv");
    vk::raii::ShaderModule shaderModule = createShaderModule(shaderCode);
    vk::PipelineShaderStageCreateInfo vert;
    vert.setStage(vk::ShaderStageFlagBits::eVertex)
        .setModule(shaderModule)
        .setPName("vertMain");
    vk::PipelineShaderStageCreateInfo frag;
    frag.setStage(vk::ShaderStageFlagBits::eFragment)
        .setModule(shaderModule)
        .setPName("fragMain");

    vk::PipelineShaderStageCreateInfo modules[] = {vert, frag};

    std::vector dynamicStates = {
        vk::DynamicState::eViewport,
        vk::DynamicState::eScissor};
    vk::PipelineDynamicStateCreateInfo dynamicState;

    dynamicState.setDynamicStateCount(static_cast<uint32_t>(dynamicStates.size()))
        .setPDynamicStates(dynamicStates.data());

    createDescriptorSetLayout();
    vk::PipelineVertexInputStateCreateInfo vertexInputInfo;
    auto bindingDesc = Vertex::getBindingDescription();
    auto attrDesc = Vertex::getAttributDescriptions();
    vertexInputInfo.setVertexBindingDescriptionCount(1)
        .setPVertexBindingDescriptions(&bindingDesc)
        .setVertexAttributeDescriptionCount(attrDesc.size())
        .setPVertexAttributeDescriptions(attrDesc.data());

    vk::PipelineInputAssemblyStateCreateInfo inputAssembly;
    inputAssembly.setTopology(vk::PrimitiveTopology::eTriangleList);

    // vk::Viewport{0.0f, 0.0f, static_cast<float>(swapchainExtent.width), static_cast<float>(swapchainExtent.height), 0.0f, 1.0f};
    // vk::Rect2D{vk::Offset2D{0, 0}, swapchainExtent};

    vk::PipelineViewportStateCreateInfo viewportInfo;
    viewportInfo.setViewportCount(1)
        .setScissorCount(1);
    // 设置Rasterizer
    vk::PipelineRasterizationStateCreateInfo rasterizer({}, vk::False, vk::False, vk::PolygonMode::eFill, vk::CullModeFlagBits::eBack, vk::FrontFace::eCounterClockwise, vk::False, 0.0f, 0.0f, 1.0f, 1.0f);
    rasterizer.setLineWidth(1.0f);

    vk::PipelineMultisampleStateCreateInfo multiSampling;
    multiSampling.setRasterizationSamples(vk::SampleCountFlagBits::e1).setSampleShadingEnable(vk::False);
    // 设置ColorBlend
    vk::PipelineColorBlendAttachmentState colorBlendAttachment;
    colorBlendAttachment.setColorWriteMask(vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG | vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA)
        .setBlendEnable(vk::True)
        .setSrcColorBlendFactor(vk::BlendFactor::eSrcAlpha)
        .setDstColorBlendFactor(vk::BlendFactor::eOneMinusSrcAlpha)
        .setColorBlendOp(vk::BlendOp::eAdd)
        .setSrcAlphaBlendFactor(vk::BlendFactor::eOne)
        .setDstAlphaBlendFactor(vk::BlendFactor::eZero)
        .setAlphaBlendOp(vk::BlendOp::eAdd);
    vk::PipelineColorBlendStateCreateInfo colorBlend;
    colorBlend.setLogicOpEnable(vk::False)
        .setLogicOp(vk::LogicOp::eCopy)
        .setAttachmentCount(1)
        .setPAttachments(&colorBlendAttachment);
    // 创建管线布局
    vk::PipelineLayoutCreateInfo layoutInfo;
    layoutInfo.setSetLayoutCount(1)
        .setPSetLayouts(&*descriptorSetLayout)
        .setPushConstantRangeCount(0);
    m_layout = vk::raii::PipelineLayout(LumineContext::Get().Device(), layoutInfo);

    // 设置深度测试
    vk::PipelineDepthStencilStateCreateInfo depthStencil{};
    depthStencil.setDepthTestEnable(true)
        .setDepthWriteEnable(true)
        .setDepthCompareOp(vk::CompareOp::eLess)
        .setDepthBoundsTestEnable(false)
        .setStencilTestEnable(false);
    // 创建渲染管线
    vk::PipelineRenderingCreateInfo info;
    info.setColorAttachmentCount(1)
        .setPColorAttachmentFormats(&format)
        .setDepthAttachmentFormat(TextureManager::depth[0].Format());

    vk::GraphicsPipelineCreateInfo pipelineInfo;

    pipelineInfo.setPNext(info)
        .setPInputAssemblyState(&inputAssembly)
        .setStageCount(2)
        .setPStages(modules)
        .setPVertexInputState(&vertexInputInfo)
        .setPViewportState(&viewportInfo)
        .setPRasterizationState(&rasterizer)
        .setPMultisampleState(&multiSampling)
        .setPColorBlendState(&colorBlend)
        .setPDynamicState(&dynamicState)
        .setLayout(m_layout)
        .setRenderPass(nullptr)
        .setSubpass(0)
        .setBasePipelineHandle(VK_NULL_HANDLE)
        .setBasePipelineIndex(-1)
        .setPDepthStencilState(&depthStencil);

    m_pipeline = vk::raii::Pipeline(LumineContext::Get().Device(), nullptr, pipelineInfo);
}

std::vector<char> Lumine::LuminePipeline::readFile(const std::string &filename)
{
    std::ifstream file(filename, std::ios::ate | std::ios::binary);
    if (!file.is_open())
    {
        throw std::runtime_error("failed to openfile");
    }
    std::vector<char> buffer(file.tellg());
    file.seekg(0, std::ios::beg);
    file.read(buffer.data(), static_cast<std::streamsize>(buffer.size()));
    file.close();
    return buffer;
}

vk::raii::ShaderModule Lumine::LuminePipeline::createShaderModule(const std::vector<char> &code)
{
    vk::ShaderModuleCreateInfo info;
    info.setCodeSize(code.size() * sizeof(char))
        .setPCode(reinterpret_cast<const uint32_t *>(code.data()));
    vk::raii::ShaderModule shader{LumineContext::Get().Device(), info};
    return shader;
}
